#include <stdio.h>
#include <stdlib.h>
#include "task.h"
#include "lpc17xx.h"
#include "kernel.h"
#include "message_queue.h"
#include "sem.h"
#include "heap.h"
#if HOOKS_ENABLED
#include "hooks.h"
#endif

void Task1(void *args);
void Task2(void *args);
void Task3(void *args);
void Task4(void *args);
void Task5(void *args);
void Task6(void *args);

const int j = 1;
#define is_little_endian() ((*(char *) &j) == 1)
/* prios increase from 0 to 32*/
#define TASK1_PRIO 1
#define TASK2_PRIO 2
#define TASK3_PRIO 3
#define TASK4_PRIO 4
#define TASK5_PRIO 5
#define TASK6_PRIO 6

OSStackType Stack1[STACK_SIZE];
OSStackType Stack2[STACK_SIZE];
OSStackType Stack3[STACK_SIZE];
OSStackType Stack4[STACK_SIZE];
OSStackType Stack5[STACK_SIZE];
OSStackType Stack6[STACK_SIZE];


queue *task6Q;
sem *s;
LIST_HEAD(list);

int main()
{
	TCB *tmp;
	//currentTCB = malloc(sizeof(TCB));
	//highestTCB = malloc(sizeof(TCB));
	/*this should be called somewhere else*/
	uint_8 *buf = malloc(32 * sizeof(uint_8));
	SystemInit();
	
	uKern_Init();
	/* create ur tasks */
	task_create(TASK1_PRIO, Task1, NULL, STACK_SIZE, &Stack1[STACK_SIZE - 1]);
	task_create(TASK2_PRIO, Task2, NULL, STACK_SIZE, &Stack2[STACK_SIZE - 1]);
	task_create(TASK3_PRIO, Task3, NULL, STACK_SIZE, &Stack3[STACK_SIZE - 1]);
	task_create(TASK4_PRIO, Task4, NULL, STACK_SIZE, &Stack4[STACK_SIZE - 1]);
	task_create(TASK5_PRIO, Task5, NULL, STACK_SIZE, &Stack5[STACK_SIZE - 1]);
	task_create(TASK6_PRIO, Task6, NULL, STACK_SIZE, &Stack6[STACK_SIZE - 1]);
	/* buggy method. dynamic task allocation causes bugs, since we don't have heap reserved space */
	//task_create(TASK1_PRIO, Task1, NULL, STACK_MIN_SIZE);
	//task_create(TASK2_PRIO, Task2, NULL, STACK_MIN_SIZE);
	
	
	LPC_GPIO1->FIODIR |= ( 1 << 23);
	LPC_GPIO1->FIODIR |= ( 1 << 21);
	LPC_GPIO1->FIODIR |= ( 1 << 20);
	LPC_GPIO1->FIODIR |= ( 1 << 18);
	
	/*init other services*/
	task6Q = queueCreate(10, sizeof(uint_32));
	s = sem_init(1);

	StartOS();
	
	/* We actually do not expect to ever reach here */
}

//factorial of 12
void Task1(void *args)
{
	int i = 0;
	uint_32 fact = 1;
	while(1){
		fact = 1;
		for (i = 0; i < 5; i++){
			;;
		}
		for (i = 1; i < 10; i++)
			fact = fact*(i + 1);
		
		LPC_GPIO1->FIOPIN ^= (1 << 18);
		timeDelay(100);
	}
}

//prime numbas (stop after 10 first)
void Task2(void *args)
{
	int i,j;
	uint_32 primes[100];
	uint_8 found = 0;
	int cntr = 0;
	while(1){
		
		for (i = 0; i < 100 ; i++){
			for (j = 2; j < i; j++){
				found = 1;
				if (((i % j) == 0)) {
					found = 0;
					break;
				}
			}
			if (found){
				primes[cntr++ % 100] = i;  // this array overlaps with our stack after index 0x51  or sth.. that is very weird.
				found = 0; 
				//yield();//TaskEnable(TASK1_PRIO);
			}
		}
		LPC_GPIO1->FIOPIN ^= (1 << 20);
		timeDelay( 200);
	}
}
/* fibonacci task */
void Task3(void *args)
{	
	
	uint_32 fibonacci[100];
	int i;
	while(1){
		fibonacci[0] = 0;
		fibonacci[1] = 1;
		for (i = 2; i < 100; i++)
			fibonacci[i] = fibonacci[i - 1] + fibonacci[(i - 2)];
		LPC_GPIO1->FIOPIN ^= (1 << 21);
		queueSendToTail(task6Q, (void *)&fibonacci[3]);
		queueSendToTail(task6Q, (void *)&fibonacci[4]);
		queueSendToTail(task6Q, (void *)&fibonacci[5]);
		queueSendToTail(task6Q, (void *)&fibonacci[6]);
		sem_release(s);
		timeDelay(300);
		
		
	}
}
/* hopelessly starving task */
void Task4(void *args){
	while(1){
		sem_get(s, 0);
		timeDelay(1000);
	}
}
/* starving task */
void Task5(void *args){
	int i; 
	while(1){
		sem_get(s, 0);
		for ( i = 0; i < 10000; i++)
			i = i + 1;
		
	}
}

void Task6(void *args){
	uint_32 *buff = (uint_32 *) malloc(sizeof(uint_32));
	while(1){
		sem_get(s, 0);
		queueReceive(task6Q, buff, 0);
		timeDelay(1000);
	}
}



#if IDLE_TASK_HOOK == 1
void idleTaskHook()
{
	/* user defiend code here*/
	/*do sth like this*/
	/*if (sleepOnIdle){
		sleep
	}*/
		;;
}
#endif
